package userRecycleModuleApi

import (
	"KumquatDrivesServices/common/res"
	"KumquatDrivesServices/enums"
	"KumquatDrivesServices/global"
	"KumquatDrivesServices/model"
	"KumquatDrivesServices/utils"
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
	"gorm.io/gorm"
)

type recoverFilesRequest struct {
	FileIds []model.SnowflakeIdType `json:"fileIds" binding:"required"`
}
type parentFileInfoAndChildFileName struct {
	parentFileInfo    model.FileModel
	childFileNameInfo map[string]model.FileModel
}

func queryOriginalParentFileInfo(fileInfos []model.FileModel, userId model.SnowflakeIdType) (
	map[model.SnowflakeIdType]parentFileInfoAndChildFileName, error) {
	var parentFileInfoMap = make(map[model.SnowflakeIdType]parentFileInfoAndChildFileName)
	for _, fileInfo := range fileInfos {
		var parentFileInfo model.FileModel
		var childFileInfos []model.FileModel
		childQuery := global.DB.Where("file_pid = ? and user_id = ? and del_flag = ?", fileInfo.FilePid, userId, enums.Normal)
		parentQuery := global.DB.Where("id = ? and  user_id = ?", fileInfo.FilePid, userId)
		if err := childQuery.Find(&childFileInfos).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, err
		}
		if err := parentQuery.Find(&parentFileInfo).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, err
		}
		childFileNameMap := make(map[string]model.FileModel)
		for _, childFileInfo := range childFileInfos {
			childFileNameMap[childFileInfo.FileName] = childFileInfo
		}
		parentFileInfoMap[fileInfo.ID] = parentFileInfoAndChildFileName{
			parentFileInfo:    parentFileInfo,
			childFileNameInfo: childFileNameMap,
		}
	}
	return parentFileInfoMap, nil
}
func (UserRecycleModuleApi) RecoverFile(c *gin.Context) {
	var req recoverFilesRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		logrus.Errorf("ShouldBindJSON err: %+v", err)
		res.FailWithCode(res.PARAM_ERR, c)
		return
	}
	if len(req.FileIds) == 0 {
		res.FailWithCode(res.PARAM_ERR, c)
		return
	}
	userId := utils.GetUserId(c)
	//查询根目录信息并转成map
	var rootChildFileInfos []model.FileModel
	rootChildFileNameInfoMap := make(map[string]model.FileModel)
	rootQuery := global.DB.Where("file_pid = ? and user_id = ? and del_flag = ?", 1, userId, enums.Normal)
	if err := rootQuery.Find(&rootChildFileInfos).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		logrus.Errorf("rootQuery err: %+v", err)
		res.FailWithCode(res.SYS_ERR, c)
		return
	}
	if len(rootChildFileInfos) > 0 {
		for _, rootChildFileInfo := range rootChildFileInfos {
			rootChildFileNameInfoMap[rootChildFileInfo.FileName] = rootChildFileInfo
		}
	}
	//查询选中的文件信息
	var fileInfos []model.FileModel
	query := global.DB.Where("id in ? and user_id = ? and del_flag = ?", req.FileIds, userId, enums.RecycleBin)
	if err := query.Find(&fileInfos).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		logrus.Errorf("Find file err: %v", err)
		res.FailWithCode(res.SYS_ERR, c)
		return
	}
	//查询父文件信息
	parentFileInfoMap, err := queryOriginalParentFileInfo(fileInfos, userId)
	if err != nil {
		logrus.Errorf("queryOriginalParentFileInfo err: %v", err)
		res.FailWithCode(res.SYS_ERR, c)
		return
	}
	tx := global.DB.Begin()
	for _, fileInfo := range fileInfos {
		//如果是文件夹，则将所有子文件变更状态为正常
		if fileInfo.IsFolder == enums.Folder {
			var recoverChildrenFileOfFolderIds []model.SnowflakeIdType
			result, fAErr := utils.FindAllSubFolderFileList(userId, fileInfo.ID, enums.Forbidden)
			if fAErr != nil {
				logrus.Errorf("FindAllSubFolderFileList err: %v", fAErr)
				res.FailWithCode(res.SYS_ERR, c)
				return
			}
			for _, childFileInfo := range result {
				recoverChildrenFileOfFolderIds = append(recoverChildrenFileOfFolderIds, childFileInfo.ID)
			}
			if len(recoverChildrenFileOfFolderIds) > 0 {
				updateQuery := tx.Model(&model.FileModel{}).Where("id in (?) and user_id=? and del_flag=?", recoverChildrenFileOfFolderIds, userId, enums.Forbidden)
				if err = updateQuery.Update("del_flag", enums.Normal).Error; err != nil {
					tx.Rollback()
					logrus.Errorf("update del_flag err: %v", err)
					res.FailWithCode(res.SYS_ERR, c)
					return
				}
			}
		}
		updateMap := map[string]any{
			"del_flag":  enums.Normal,
			"file_pid":  fileInfo.FilePid,
			"file_name": fileInfo.FileName,
		}
		parentFileMapInfo := parentFileInfoMap[fileInfo.ID]
		//如果文件名已经存在且文件类型一致，则修改文件名
		if childFileInfo, ok := parentFileMapInfo.childFileNameInfo[fileInfo.FileName]; ok && childFileInfo.IsFolder == fileInfo.IsFolder {
			updateMap["file_name"] = utils.Rename(fileInfo.FileName)
		}
		//如果父文件已经在回收站中，则将文件移动到根目录下并检查文件名是否重复，如果重复则修改文件名
		if parentFileMapInfo.parentFileInfo.DelFlag == enums.RecycleBin {
			updateMap["file_pid"] = 1
			if rootChildFileInfo, ok := rootChildFileNameInfoMap[fileInfo.FileName]; ok && rootChildFileInfo.IsFolder == fileInfo.IsFolder {
				updateMap["file_name"] = utils.Rename(fileInfo.FileName)
			}
		}
		//将文件从回收站中恢复到原目录并修改删除标志位为正常
		updateQuery := tx.Model(&model.FileModel{}).Where("id = ? and user_id = ? and del_flag = ?", fileInfo.ID, userId, enums.RecycleBin)
		if err = updateQuery.Updates(updateMap).Error; err != nil {
			tx.Rollback()
			logrus.Errorf("update del_flag err: %v", err)
			res.FailWithCode(res.SYS_ERR, c)
			return
		}
	}
	if err = tx.Commit().Error; err != nil {
		tx.Rollback()
		logrus.Errorf("Commit err: %v", err)
		res.FailWithCode(res.SYS_ERR, c)
		return
	}
	res.OkWithData(res.EmptyData, c)
}
